#include <iostream>
#include "cmdline.h"
#include <dirent.h>
#include <fstream>
#include <regex>

#if defined(_MSC_VER)
#include <direct.h>
#define GetCurrentDir _getcwd
#elif defined(__unix__)
#include <unistd.h>
#define GetCurrentDir getcwd
#else
#endif


std::string getCurrentDir();
void extractDirContent(const std::string& dirname, const std::string& filter, const std::string& regexStr, std::ofstream& outFile);
void extractFileContent(const std::string& filename, const std::string& regexStr, std::ofstream& outFile);
bool isValidFormat(const std::string& filter, const std::string& filename);


int main(int argc, char** argv) {
    // 参数解析
    cmdline::parser cmdParser;
    cmdParser.add<std::string>("dir", 'd', "dir path", true, ".");
    cmdParser.add<std::string>("match", 'm', "regex match str", true);
    cmdParser.add<std::string>("out", 'o', "out put file", false, "output.txt");
    cmdParser.add<std::string>("filter", 'f', "file extension filter", false, "*");
    cmdParser.parse_check(argc, argv);

    std::string entry;
    std::string out;
    std::string inputDir = cmdParser.get<std::string>("dir");
    std::string outputDir = cmdParser.get<std::string>("out");
    entry = inputDir[0] == '/' ? inputDir : getCurrentDir() + "/" + inputDir;
    out = outputDir[0] == '/' ? outputDir : getCurrentDir() + "/" + outputDir;
    std::ofstream outFile(out, std::ios::out);
    outFile.flush();
    extractDirContent(entry, cmdParser.get<std::string>("filter"), cmdParser.get<std::string>("match"), outFile);
    outFile.close();
    std::cout << "File write to: " << out << " successful" << std::endl;
    return 0;
}

std::string getCurrentDir()
{
    char buff[250];
    GetCurrentDir(buff, 250);
    std::string ret(buff);
    return ret;
}

void extractDirContent(const std::string& dirname, const std::string& filter, const std::string& regexStr, std::ofstream& outFile)
{
    DIR* dirHandlePtr;
    struct dirent *dirPtr;

    if( (dirHandlePtr = opendir(dirname.c_str())) == nullptr )
    {
        std::cout << "can not open dir : [" << dirname << "]" <<std::endl;
    }

    while((dirPtr = readdir(dirHandlePtr)) != nullptr)
    {
        std::string filename(dirPtr->d_name);
        std::string entry(dirname);
        entry.append("/").append(filename);
        if(filename == "." || filename == ".." || !isValidFormat(filter, filename))
        {
            continue;
        }
        if(dirPtr->d_type == 4)
        {
            extractDirContent(entry, filter, regexStr, outFile);
        }
        if(dirPtr->d_type == 8)
        {
            extractFileContent(entry, regexStr, outFile);
        }
    }
    closedir(dirHandlePtr);
}

void extractFileContent(const std::string& filename, const std::string& regexStr, std::ofstream& outFile)
{
    std::ifstream inFile(filename, std::ios::in);
    std::stringstream ss;
    ss << inFile.rdbuf();
    std::string content(ss.str());
    inFile.close();
    std::regex reg(regexStr);

    std::sregex_iterator iter(content.begin(), content.end(), reg);
    std::sregex_iterator end;

    while (iter != end)
    {
        for (int i = 1; i < iter->size(); i+=2)
        {
            outFile << (*iter)[i] << std::endl;
        }
        ++iter;
    }

}


bool isValidFormat(const std::string& filter, const std::string& filename)
{
    if(filter == "*")
    {
        return true;
    }
    else
    {
        std::string ext;
        if(filename.find('.') != -1)
        {
            ext = filename.substr(filename.find_last_of('.'));
        }
        if(filter.find(',') < 0 && filter.find('|') < 0)
        {
            return filter == ext;
        }
        else
        {
            std::regex reg(",|\\|");
            std::vector<std::string> elems(std::sregex_token_iterator(filter.begin(), filter.end(), reg, -1),
                                           std::sregex_token_iterator());
            bool fined = std::find(elems.begin(), elems.end(), ext) != elems.end();
            return fined;
        }
    }
}